﻿#pragma once

#include <cstddef>
#include <optional>
#include <utility>
#include <memory>
#include <string>
#include <mutex>

inline constexpr char NUMBER_SIZE = 10;
inline constexpr char LETTER_SIZE = 26;
inline constexpr std::size_t TABLE_SIZE = NUMBER_SIZE + LETTER_SIZE * 2;

class Decryptor final
{
public:
	struct Config;

public:
	using SizeType = std::size_t;
	using IDType = SizeType;

private:
	mutable std::mutex _mutex;
	std::shared_ptr<void> _data;

private:
	static void move(Decryptor& _left, \
		Decryptor&& _right) noexcept;

public:
	Decryptor();
	Decryptor(const Decryptor&) = delete;
	Decryptor(Decryptor&& _another) noexcept
	{
		move(*this, std::forward<Decryptor>(_another));
	}

	Decryptor& operator=(const Decryptor&) = delete;
	Decryptor& operator=(Decryptor&& _decryptor) noexcept;

	bool open(const Config& _config);
	bool open(Config&& _config);

	void close();
	void close(SizeType _count);

	std::optional<SizeType> count() const;
	std::optional<SizeType> count(IDType _id) const;

	bool complete() const;
	void execute(IDType _id);
};

struct Decryptor::Config
{
	std::string _workspace;
	std::string _command;
	std::string _password;
	std::string _counter;
	SizeType _length;

	Config() : \
		_workspace("Workspace"), \
		_command("Command.bat"), \
		_password("Password.txt"), \
		_counter("Counter.txt"), \
		_length(1) {}
};
